package com.letu.aopcache.interceptor;

import com.letu.annotation.annotation.cache.Cache;
import com.letu.aopcache.aspectj.CacheAopProxy;
import com.letu.aopcache.handler.CacheHandler;
import com.letu.aopcache.util.AopUtil;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Method;

/**
 * 对@Cache 拦截注解
 */
@Slf4j
public class CacheMethodInterceptor implements MethodInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(CacheMethodInterceptor.class);

    private final CacheHandler cacheHandler;

    private final AutoloadCacheProperties config;

    public CacheMethodInterceptor(CacheHandler cacheHandler, AutoloadCacheProperties config) {
        this.cacheHandler = cacheHandler;
        this.config = config;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try {
            if (!this.config.getAopCacheConfig().getIsenabled()) {
                return invocation.proceed();
            }
            Method method = invocation.getMethod();
            Class<?> cls = AopUtil.getTargetClass(invocation.getThis());
            if (!cls.equals(invocation.getThis().getClass())) {
                if (logger.isDebugEnabled()) {
                    logger.debug(invocation.getThis().getClass() + "-->" + cls);
                }
                return invocation.proceed();
            }
            if (logger.isDebugEnabled()) {
                logger.debug(invocation.toString());
            }
            if (method.isAnnotationPresent(Cache.class)) {
                Cache cache = method.getAnnotation(Cache.class);
                if (logger.isDebugEnabled()) {
                    logger.debug(invocation.getThis().getClass().getName() + "." + method.getName() + "-->@Cache");
                }
                return cacheHandler.proceed(new CacheAopProxy(invocation), cache);
            } else {
                // method代表接口中的方法,specificMethod代表实现类中的方法
                Method specificMethod = AopUtils.getMostSpecificMethod(method, invocation.getThis().getClass());
                if (specificMethod.isAnnotationPresent(Cache.class)) {
                    Cache cache = specificMethod.getAnnotation(Cache.class);
                    if (logger.isDebugEnabled()) {
                        logger.debug(
                                invocation.getThis().getClass().getName() + "." + specificMethod.getName() + "-->@Cache");
                    }
                    return cacheHandler.proceed(new CacheAopProxy(invocation), cache);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("缓存模块出错：", e);
        }
        return invocation.proceed();
    }

}
